
public class Parser
{
    private Scanner scanner;
    private Token currentToken;

    public SyntaxNode Parse(String codeLine)
            throws RuntimeException
    {
        scanner = new Scanner(codeLine);
        GetNextToken();
        SyntaxNode node = new SyntaxNode(SyntaxNodeType.PROGRAM);
        node.operand1 = GetNode();
        if (currentToken.GetId() != TokenId.EOF)
        {
            throw new RuntimeException(GetErrorMessage("Invalid statement syntax"));
        }
        return node;
    }

    private SyntaxNode GetNode()
            throws RuntimeException
    {
        SyntaxNode node;
        switch (currentToken.GetId())
        {
            case WHILE:
                node = new SyntaxNode(SyntaxNodeType.WHILE);
                GetNextToken();
                node.operand1 = GetVariable();
                node.operand2 = GetNode();
                break;
            case SEMICOLON:
                node = new SyntaxNode(SyntaxNodeType.EMPTY);
                GetNextToken();
                break;
            case RIGHT:
            case LEFT:
            case FORWARD:
            case BACKWARD:
            case GO:
            case STOP:
            case ATTACK:
            case WORK:
            case SAY:
                node = new SyntaxNode(SyntaxNodeType.EMPTY);
                node.operand1 = new SyntaxNode(SyntaxNodeType.COMMAND, currentToken.GetInfo());
                GetNextToken();
                if (currentToken.GetId() != TokenId.SEMICOLON)
                {
                    throw new RuntimeException(GetErrorMessage("';' expected"));
                }
                GetNextToken();
                if (currentToken.GetId() != TokenId.EOF)
                {
                    node.operand2 = GetNode();
                }
                break;
            default:
                node = new SyntaxNode(SyntaxNodeType.EMPTY);
                break;
        }

        return node;
    }

    private SyntaxNode GetVariable()
            throws RuntimeException
    {
        if (currentToken.GetId() != TokenId.LEFT_ROUND_BRACKET)
        {
            throw new RuntimeException(GetErrorMessage("'(' expected"));
        }
        GetNextToken();
        if (currentToken.GetId() != TokenId.VARIABLE)
        {
            throw new RuntimeException(GetErrorMessage("Variable expected"));
        }
        SyntaxNode node = new SyntaxNode(SyntaxNodeType.VARIABLE, currentToken.GetInfo());
        GetNextToken();
        if (currentToken.GetId() != TokenId.RIGHT_ROUND_BRACKET)
        {
            throw new RuntimeException(GetErrorMessage("')' expected"));
        }
        GetNextToken();
        return node;
    }

    private void GetNextToken()
    {
        currentToken = scanner.GetNextToken();
    }

    private String GetErrorMessage(String msg)
    {
        return "Parse error: " + msg;
    }
}
